﻿#ifndef QDISPLAYWIDGET_H
#define QDISPLAYWIDGET_H

#include <QWidget>
#include <QTime>
#include <QTimer>
//#include "QueueRT.h"
#include "myC11Queue.h"
#include "common.h"
#include "ui_basePlayWnd.h"
#include "ui_exportStatDlg.h"
#include <QtConcurrent>
#include "tipDlgs.h"

const static QString global_decoder_name[PixelSamplingMax] = { "", "YUV422-1080i","YUV422" };
class QDisPlayWidget;

class BaseDisParentWnd
	:public QWidget
{
	Q_OBJECT

public:

	BaseDisParentWnd(QWidget* parent, TCCDInfo& ccdInfo,QString strDev, QString strNam);
	~BaseDisParentWnd();

	QDisPlayWidget* DisPlayWnd() const { return _disPlayWnd; }

	void toShowNormal()
	{
		ui.widget_ctrl->hide();
		if (m_strNam != "")
		{
			ui.label_playInfo->setText(m_strNam.split("_")[0]);
		}
	}

	void setSimulateUi()
	{
		ui.btn_faster->hide();
		ui.btn_lower->hide();
	}

	void toShowRecPlay()
	{
		ui.label_playInfo->setText(m_strNam);
		ui.widget_ctrl->show();
	}

	void resizeWndToNormal();

	void toSetSliderRange(int min,int max)
	{
		ui.playSlider->setRange(min, max);
		ui.playSlider->setValue(min);
	}

	QScrollArea* getScrollArea()
	{
		return ui.scrollArea;
	}

	QString getCCDNam()
	{
		return _ccdInfo.m_strCCDNam;
	}

	QString getDevNam()
	{
		return _devNam;
	}

	void setLableText(QString strText)
	{
		ui.label_playInfo->setText(strText);
	}

	bool eventFilter(QObject *watched, QEvent *event);

	void adjustScrollBar(float factor);

public slots :

	void zoomIn();

	void zoomOut();

	void zoom11();

	void restore();

protected:

	virtual void customEvent(QEvent *event);
//	virtual int heightForWidth(int) const;

	virtual QPaintEngine * paintEngine() const;

protected slots:

private:
	Ui::basePlayerWnd ui;
	QDisPlayWidget* _disPlayWnd;
	QString m_strNam;
	QIcon* _playIco;
	QIcon* _pauseIco;
	TCCDInfo& _ccdInfo;
	QString _devNam;
};

// 线程任务 [11/4/2016 ejitec]
class StreamWorker
	:public QObject
{
	Q_OBJECT

public:

	explicit StreamWorker(QDisPlayWidget* ptCaller);

signals :

	void evt_refresh(); 
	void evt_workFinish();

public slots :

	void on_DoStreamRecReq();
	void on_DoSimuRealReq();
	void on_DoRecExport();
	void on_DoStreamRealReq();

private:

	QDisPlayWidget* m_ptCaller;
};


// 录像导出进度条
class recExpStatDlg;
class simuStatDlg;
class eagle_cmlink_export_info;

class QDisPlayWidget : public QWidget
{
	Q_OBJECT

	QThread m_Thread;

public:

	enum
	{
		E_RIGHTMENU_SNAP,
		E_RIGHTMENU_STATISTIC,
		E_RIGHTMENU_PIXEL,
		E_RIGHTMENU_OUTFORMAT,
		E_RIGHTMENU_DECODE,
		E_RIGHTMENU_UPDOWN,
		E_RIGHTMENU_LEFTRIGHT,
		E_RIGHTMEUN_SCALE,
		E_RIGHTMENU_EXTRAPARAM,
		E_RIGHTMENU_MAX,
	};

	const QString m_strRightMenuItems = tr("保存图像,分析统计,显示像素值,输出格式,位宽转换,上下颠倒,左右颠倒,显示图像");

	QDisPlayWidget(QWidget *parent, QString name = "No Video");

	~QDisPlayWidget();

    CURRENT_DISPLAY_TYPE getPlayType();

	void setContexMenu();  // 由 父类调用

 	virtual void paintEvent(QPaintEvent *event);

	virtual void mousePressEvent(QMouseEvent *event);

	virtual void mouseReleaseEvent(QMouseEvent *event);

	virtual void mouseMoveEvent(QMouseEvent *event);

	//virtual void wheelEvent(QWheelEvent *event);

	virtual QPaintEngine * paintEngine() const;

	virtual void mouseDoubleClickEvent(QMouseEvent *event);

	virtual void customEvent(QEvent *event);

	bool allocMemoryForQueen(int w, int h, int nDepth,int pixSIze);

	void freeMemory();

	CQueueRT<DisplayFrameData>& QueenData() { return m_cQueenData; }

	QString get_decoder() { return _decoder_name; }

	bool set_decoder(unsigned int sampling_type, bool start)
	{
		if (sampling_type < PixelSamplingMax && sampling_type > 0)
		{
			_decoder_name = global_decoder_name[sampling_type];
			QString new_decoder = _decoder_name;
			EagleConfigFile::getInstance()->SetDeviceCameraDecoderName(m_nDevID, m_nCCDID, new_decoder);
			m_bBitChange = true;
		}

#ifdef CHENGGS_VERSION

		if (CHENGGS_VERSION == 2)
		{
			if (start)
			{
				if (m_nCCDID == 3)
					_decoder_name = "CHENGColor";
				if (m_nCCDID == 4)
					_decoder_name = "MonoDecoder";
			}
			else
			{
				_decoder_name = "Linear";
			}
		}
		else if (CHENGGS_VERSION == 3)
		{
			if (start)
			{
				if (m_nCCDID == 2)
					_decoder_name = "CHENGColor";
				if (m_nCCDID == 3)
					_decoder_name = "MonoDecoder";
			}
			else
			{
				_decoder_name = "Linear";
			}
		}

#endif
		return false;
	}

	QString get_read_format(){ return _format_name; }

	void renderStreamData(DisplayFrameData* pData,QPainter* p);
	EvtThreadHandler* getHandler()
	{
		return m_ptJobHander;
	}

	// 所有线程操作 [11/8/2016 ejitec]
	int on_DoStreamRecReq();  // 录像回放

	int on_DoSimuRealReq();  // 仿真播放
	 
	int on_DoRecExportAsync(int nIndex);     // 异步录像导出 bmp jpg head
	int on_DoRecExportSync();     // 录像导出 同步录像和rawstream

	int on_DoStreamRealReq();  // 实时播放

	BaseDisParentWnd* getParent()
	{
		return _parent;
	}

	void setCaller(BaseDisParentWnd* ctx)
	{
		_parent = ctx;
		setContexMenu();
	}

	bool InCenter() const { return m_bInCenter; }

	void InCenter(bool val) 
	{ 
		m_bInCenter = val; 

		if (m_bInCenter && m_bRecPlay)
		{
			getParent()->toShowRecPlay();
		}
		else
		{
			getParent()->toShowNormal();
		}
		//_parent->resizeWndToNormal();
	}

	void drawLabelText(DisplayFrameData*pData = NULL,QPoint pos = QPoint(0,0));

	void InitExportStatusDlg(QString title);
	void HideExportStatusDlg();
	// 仿真提示框 [11/28/2017 xystar]
	void InitSimulaStatusDlg(QString title);
	void ShowOpRetMsg(QString title);
	bool &get_display_mode_change_flag() { return is_display_mode_changed; }
	bool GetUpDownIsReversed() { return UpDownIsReservsed; }
	bool GetLeftRightIsReversed() { return LeftRightIsReservsed; }
	void UpDownReversed()
	{
		UpDownIsReservsed = !UpDownIsReservsed;
		//if (display_state != CURRENT_DISPLAY_STATE::DISPLAY_STATE_DISPLAYING)
		is_display_mode_changed = true;
		EagleConfigFile::getInstance()->SetDeviceCameraUpDownReverse(m_nDevID, m_nCCDID, UpDownIsReservsed);
		update();
	}

	void LeftRightReversed()
	{
		LeftRightIsReservsed = !LeftRightIsReservsed;
		//if (display_state != CURRENT_DISPLAY_STATE::DISPLAY_STATE_DISPLAYING)
		is_display_mode_changed = true;
		EagleConfigFile::getInstance()->SetDeviceCameraLeftRightReverse(m_nDevID, m_nCCDID, LeftRightIsReservsed);
		update();
	}

	bool IsDisplayIng()
	{
		return m_bRealPlay || m_bRecPlay || m_bSimuPlay;
	}
	
	bool IsExpOrCheck()
	{
		return m_bChecking || m_bExporting;
	}

	void PostEvent(MessageCmd* cmd)
	{
		return qApp->postEvent(this, cmd);
	}

	bool SendEvent(MessageCmd* cmd)
	{
		return qApp->sendEvent(this, cmd);
	}

	bool& isExporting()
	{
		return m_bExporting;
	}

	DisplayFrameData * getCurrentDisplayData();

protected:

	void drawAviExtentText(DisplayFrameData& data, QImage& image);
	void prepStartFutureWatcher();
	void endFutrueWatcher();

	
	void timerEvent(QTimerEvent *event);
	bool preperExpRecord();
	virtual void contextMenuEvent(QContextMenuEvent * event);
	quint64 ExportCheckThread(ExportContext *context);
	
#ifdef WITH_FFMPEG
				  //////////////////////////////////////////////////////////////////////////
	//  video output [3/20/2017 ejitec]
	AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height);
	bool open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg);
	/* Add an output stream. */
	bool add_stream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id, ExportContext* context);

#endif // 0
	
	void setVideoCtx();
	QVariant asyncGetOneRecordFrame(int n);
	QVariant asyncExportCheckFrame(int n);

public slots:

	void on_btnPlay();
	void on_btnFaster();
	void on_btnLower();
	void on_btnPrev();
	void on_btnNext();
	void on_slidValueChange(int n);
	void on_getOneRecordFrame(int n);
	void on_expRelatedAsyncEnd();
	void on_scrollBarValueChange(int n);


protected slots:

	void on_ThreadFinish(TCbJob tJob);

signals:

	void evt_dbClick(QMouseEvent *e);
	// 包含 录像 实时 仿真 等操作 [10/25/2016 ejitec]
	void evt_recReq();
	void evt_recExp();
	void evt_realReq();
	void evt_simuReq();
	// 由窗口发送到 主界面
	void evt_stopRec();
	void evt_setSlider(int n);
	void evt_setPlayStatus(bool);
	void evt_setExpStatBar(int n);

private:

	bool m_bRealPlay;
	bool m_bRecPlay;
	bool m_bSimuPlay;
	bool m_bRecPause;
	bool m_bChecking;
	bool m_bExporting;
	bool m_bTheadAlive;
	bool m_bFullScreen;
	bool m_bDrawRecStart;
	bool m_bHaveReserveThread;

	QImage m_Image;
	QPoint m_startPt;
	QPoint m_endPt;

	EaglePostEventManager m_UiTask;  // 非UI线程中 UI线程管理类 刷新界面 
	QTime m_time;
	QString m_strNam;
	//队列 [3/22/2017 ejitec]
	CQueueRT<DisplayFrameData> m_cQueenData;

	int m_nDevID;
	int m_nCCDID;
	// 线程对象
	EvtThreadHandler* m_ptJobHander;
	StreamWorker m_Worker;
	//std::vector<StreamWorker*> m_ExpWorkers;  // 用于 录像导出 效果不理想
	QFutureWatcher<QVariant> *m_pAsyncRecExping;
	QString _decoder_name;
	QString _format_name;
	bool is_display_mode_changed;  // 上下 颠倒
	bool m_bBitChange;  // 解码 和 位宽 改变
	bool m_bInCenter;   // 窗口是否居中
	BaseDisParentWnd* _parent;
	// 导出进度条
	recExpStatDlg* status_dlg;
	simuStatDlg* simu_dlg;
	bool	UpDownIsReservsed;
	bool	LeftRightIsReservsed;

	// 右键菜单 [12/8/2016 ejitec]
	QMenu* _contextMenu;

	// 等待锁 [12/1/2017 xystar]
	QMutex _threadLock;

public:

	int DevID() const { return m_nDevID; }
	void DevID(int val) { m_nDevID = val; }
	int CCDID() const { return m_nCCDID; }
	void CCDID(int val) { m_nCCDID = val; }
	//virtual void resizeEvent(QResizeEvent *event);
	static __inline int getIdealThreadCnt()
	{
		return qMax(QThread::idealThreadCount(), EagleConfigFile::getInstance()->m_nAsyncThreadCnt);
	}

	BaseDisplayContext* m_tOPCtx;
	
	XGSExpParams* getXGSExpParms()
	{
		return &m_ExpParms;
	}
	
	void setExpParams(QString strText)
	{
		QStringList sValues = strText.split("|");
		if (sValues.size() == 3)
		{
			std::get<0>(m_ExpParms) = sValues[0].toInt();
			std::get<1>(m_ExpParms) = sValues[1].toInt();
			std::get<2>(m_ExpParms) = sValues[2].toInt();
		}
	}


protected:

	int InitSimulatePlay();
	// nMode 0 -- start  1 --- prev  2 --- next
	void SetCmlink_export_info(int nStart, int framNum,eagle_cmlink_export_info*);

private:

	//  GT_CMD_SEND_CCD_DETECT_INFO [3/20/2017 ejitec]
	quint32 detect_column;
	quint32 detect_line;
	quint32 detect_rate;
	quint8 lose_frame;
	XGSExpParams m_ExpParms;

	// 拖动滑动条时的  偏移坐标 以便绘制居中十字
	QPoint m_scrollOffsetP;
};


class simuStatDlg
	:public QDialog
{
	Q_OBJECT

public:
	simuStatDlg(QWidget* parent)
		:QDialog(parent)
	{
		this->setWindowFlags(/*Qt::WindowStaysOnTopHint |*/ Qt::FramelessWindowHint | Qt::Tool);
		this->setFixedSize(200, 50);
		_labInfo = new QLabel(this);
		_labInfo->setAlignment(Qt::AlignCenter);
		_labInfo->setWordWrap(true);
		QVBoxLayout* vLay = new QVBoxLayout(this);
		vLay->addWidget(_labInfo);
	}

	void setWaitText(QString strText)
	{
		_labInfo->setText(strText);
	}

	void toShow()
	{
		this->setWindowModality(Qt::WindowModal);  // 只阻塞父类 [6/14/2017 xystar]
		this->show();
	}


private:
	QLabel* _labInfo;

};

// 导出进度条 对话框 [11/9/2016 ejitec]
class recExpStatDlg
	:public QDialog
{
	Q_OBJECT

public:

	recExpStatDlg(QWidget* parent, QString name)
		:QDialog(parent)
	{
		ui.setupUi(this);

		ui.label_task->setText(name);
		setFixedSize(316, 99);
		_timer.setInterval(500);
		ui.label_run->setText("");

		connect(ui.btn_cancle, &QPushButton::clicked, this, [=]()
		{
			Q_ASSERT(_ctx != NULL);
			_ctx->cancel_export();
			_timer.stop();
			this->reject();
			qDebug() << "recExpStatDlg hide here!!";
			emit evt_cancel();
		});

		connect(&_timer, &QTimer::timeout, this, [this]()
		{
			ui.label_run->setText(QString(tr(" %1 秒")).arg(_time.elapsed() / 1000,4,10,QChar('0')));
		});

		connect(qobject_cast<QDisPlayWidget*>(parent), &QDisPlayWidget::evt_setExpStatBar, this, [=](int n)
		{
			ui.probar->setValue(n);
		});

	}

	void SetContext(BaseDisplayContext* tmpctx)
	{
		ExportContext* ctx = (ExportContext*)tmpctx;
		_ctx = ctx;
		ui.probar->setRange(0,_ctx->get_export_frame_num());
		ui.probar->setValue(0);
		_time.start();
		_timer.start();
		ui.label_start->setText(QDateTime::currentDateTime().toString("hh时mm分ss秒"));
		//this->setAttribute(Qt::WA_ShowModal);
 		this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint);
		this->setWindowModality(Qt::WindowModal);  // 只阻塞父类 [6/14/2017 xystar]
 		this->show();
		//this->exec(); // 会阻塞消息循环
	}

	QProgressBar* getProBar()
	{
		return ui.probar;
	}

	long getValue()
	{
		return ui.probar->value();
	}

	void toClose()
	{
		_timer.stop();
		this->accept();
	}
signals:
	void evt_cancel();


private:
	Ui::exportStatDlg ui;
	ExportContext *_ctx;
	QTimer _timer;
	QTime _time;
};

#endif // QDISPLAYWIDGET_H
